package com.yc.spring.mvc.core;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.yc.spring.mvc.core.annotation.ResponseBody;


/**
 * 请求分发器
 * company 源辰信息
 * @author navy
 * @date 2021年4月1日
 */
public class DispatcherServlet extends HttpServlet{
	private static final long serialVersionUID = -8260301836959362840L;
	
	private String contextConfigLocation = "application.properties";
	private FrameworkCore frameworkCore = null;
	
	@Override
	public void init(ServletConfig config) throws ServletException{
		String temp = config.getServletContext().getInitParameter("contextConfigLocation");
		
		if (!StringUtil.chekNUll(temp)) {
			contextConfigLocation = temp;
		}
		
		//  开始核心代码的解析运行
		frameworkCore = new FrameworkCore(contextConfigLocation);
	}
	
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws  ServletException,IOException{
		// 获取请求地址
		String url = request.getRequestURI(); // /myspringmvc/user/login
		
		// 获取请求的项目名
		String contextPath = request.getContextPath(); // /myspringmvc
		
		// 获取请求的资源名(不包括项目名在内)
		url = url.replaceFirst(contextPath, "").replaceAll("/+", "/"); // /user/login
		
		//判断请求地址中是否有参数
		if(url.contains("?")) { // 说明请求地址中带有参数
			url = url.substring(0, url.indexOf("?"));
			
		}
		//根据请求地址从HandlerMapper中获取处理方法
		HandlerMapperInfo mapperInfo = frameworkCore.getMapper(url);
		
		//如果获取不到，则当成静态资源访问
		if(mapperInfo == null) {//说明没有对应的处理方法，则当成静态资源去访问，如果也没有对应的静态资源，则报错404
			//处理静态资源返回
			HandleResponse.handlerStaticResource(response, request.getServletContext().getRealPath("") + url.substring(1));
			return;
		}
		
		try {
			//如果有，则反向激活这个方法
			Method method = mapperInfo.getMethod();//获取处理这个请求的方法
			
			//给这个方法的形参注值 -> 值从请求中来
			Object[] args = HandleRequest.handle(request, method, response);
			
			//获取这个方法的返回值
			Object obj = method.invoke(mapperInfo.getObj(), args);
			
			//判断这个方法上是否有@ResponseBody注解，即需要以什么格式返回此数据
			if(method.isAnnotationPresent(ResponseBody.class)) {//说明要以json格式返回
				//以json格式返回结果
				HandleResponse.sendJson(response, obj);
				return;
			}
			
			//这默认当成页面跳转地址
			String path = String.valueOf(obj);
			if(path.startsWith("redirect:")) {//说明要以重定向方式跳转
				path = path.replaceFirst("redirect:", "");
				if(path.startsWith("/")) {//说明用户给的是绝对路径，即以项目路径开始计算
					path = contextPath + path;
				}
				response.sendRedirect(path);
				return;
			}
			
			//否则就以内部转发方式
			request.getRequestDispatcher(path).forward(request, response);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}	
	}
}
